<script setup>
import {ref, onMounted, computed} from 'vue'
import { sessionApi, saveExamApi, procExamsApi, oneExamApi, pageExamsApi } from '@/commons/api'
import routes from '@/commons/router'
import Loader from '@/components/loader/Loader'
import { CScrollbar } from 'c-scrollbar'
import Msg from '@/components/message'
import Confirm from '@/components/confirm'
import Pager from '@/components/pager/Pager'
import Upload from '@/components/upload/Upload'
import Datepicker from '@vuepic/vue-datepicker'
import '@vuepic/vue-datepicker/dist/main.css'
import { formatDatetime, formatDateRange } from '@/commons/filter'
import { nanoid } from 'nanoid'
import QRCode from 'qrcode'

const loadShow = ref(false)

// 界面挂载前处理
onMounted(() => {
  // 获取用户会话信息
  checkAuth()
})

let procAuth = {
  saveAuth: false,
  procAuth: false
}
// checkAuth 获取权限
const checkAuth = async () => {
  loadShow.value = true
  try {
    const res = await sessionApi()
    if (res.code === import.meta.env.VITE_SUCCESS_CODE) {
      const userBtnCode = res.data.btnCodes
      procAuth = {
        saveAuth: userBtnCode.indexOf('1002020101') !== -1,
        procAuth: userBtnCode.indexOf('1002020102') !== -1
      }
      await page(0, 1)
    } else {
      localStorage.removeItem("token")
      Msg({ kind: 'error', txt: res.msg })
      routes.replace('/login')
    }
    loadShow.value = false
  } catch (e) {
    loadShow.value = false
    Msg({ kind: 'error', txt: '系统错误，请联系管理员！' + e })
  }
}

const schObj = {
  keywords: '',
  offset: 0,
  limit: 20
}
const schRef = ref(schObj)
const total = ref(0)
const curPage = ref(1)
const examList = ref([])
const hasData = ref(false)
// page 列表展示
const page = async (offset, cur) => {
  schRef.value.offset = offset || 0
  curPage.value = cur || 1
  hasData.value = false
  const res = await pageExamsApi(schRef.value)
  if(res.code === import.meta.env.VITE_SUCCESS_CODE && res.data) {
    hasData.value = true
    total.value = res.data.total
    examList.value = res.data.list
  }
}

// search 筛选
const schShow = ref(false)
const search = () => {
  schShow.value = !schShow.value
}

// clrSch 重置搜索框
const clrSch = () => {
  schRef.value = schObj
  page(0, 1)
}

const fileObj = ref({ id: nanoid(), name: '', url: '' })
let curExamId = nanoid(21)
const examForm = ref({
  examId: '',
  title: '',
  score: 100,
  examTime: 0,
  beginTime: 0,
  endTime: 0,
  imgNames: '',
  imgUrls: '',
  deptId: '',
  remarks: ''
})
// add 新增
const showModal = ref(false)
const times = ref([])
const add = () => {
  showModal.value = true
  examForm.value.examId = curExamId
  examForm.value.saveType = 1
  optList.value = [
    { optId: nanoid(21), examId: curExamId, kind: 1, nums: 80, score: 0.5, remarks: '' },
    { optId: nanoid(21), examId: curExamId, kind: 2, nums: 20, score: 1.0, remarks: '' },
    { optId: nanoid(21), examId: curExamId, kind: 3, nums: 20, score: 2.0, remarks: '' },
    { optId: nanoid(21), examId: curExamId, kind: 4, nums: 0, score: 0.0, remarks: '' },
    { optId: nanoid(21), examId: curExamId, kind: 5, nums: 0, score: 0.0, remarks: '' },
    { optId: nanoid(21), examId: curExamId, kind: 6, nums: 0, score: 0.0, remarks: '' }
  ]
}
// update 修改
const update = async (examId) => {
  const res = await oneExamApi({ examId })
  if(res.code === import.meta.env.VITE_SUCCESS_CODE) {
    showModal.value = true
    examForm.value = res.data
    examForm.value.saveType = 2
    if(res.data.optList && res.data.optList.length > 0) {
      optList.value = res.data.optList
      optList.value.forEach(opt => {
        opt.score = parseFloat(opt.score)
      })
    } else {
      optList.value = [
        { optId: nanoid(21), examId: examId, kind: 1, nums: 80, score: 0.5, remarks: '' },
        { optId: nanoid(21), examId: examId, kind: 2, nums: 20, score: 1.0, remarks: '' },
        { optId: nanoid(21), examId: examId, kind: 3, nums: 20, score: 2.0, remarks: '' },
        { optId: nanoid(21), examId: examId, kind: 4, nums: 0, score: 0, remarks: '' },
        { optId: nanoid(21), examId: examId, kind: 5, nums: 0, score: 0, remarks: '' },
        { optId: nanoid(21), examId: examId, kind: 6, nums: 0, score: 0, remarks: '' }
      ]
    }
    // 设置起止时间
    times.value = []
    const beginDate = new Date(examForm.value.beginTime * 1000)
    const endDate = new Date(examForm.value.endTime * 1000)
    times.value.push(beginDate)
    times.value.push(endDate)
    if(res.data.imgNames) {
      fileObj.value = { id: nanoid(), name: res.data.imgNames, url: res.data.imgUrls }
    }
  } else {
    Msg({ kind: 'error', txt: res.msg })
  }
}
// save 保存提交
const save = async () => {
  let title = examForm.value.title
  if(title === '' || title.length > 80) {
    Msg({ kind: 'warn', txt: '名称不能为空，且长度不超过80个字符！' })
    return
  }
  loadShow.value = true
  try {
    // 起止时间转换为时间戳
    examForm.value.beginTime = times.value && times.value.length===2 && times.value[0] ? times.value[0].getTime()/1000 : 0
    examForm.value.endTime = times.value && times.value.length===2 && times.value[1] ? times.value[1].getTime()/1000 : 0
    examForm.value.imgNames = fileObj.value.name
    examForm.value.imgUrls = fileObj.value.url
    examForm.value.optList = optList.value
    const res = await saveExamApi(examForm.value)
    if(res.code === import.meta.env.VITE_SUCCESS_CODE) {
      closeModal(1)
      await page(0, 1)
      Msg({ kind: 'success', txt: '恭喜您，试卷保存成功！' })
    } else {
      Msg({ kind: 'error', txt: res.msg })
    }
    loadShow.value = false
  } catch (e) {
    loadShow.value = false
    Msg({ kind: 'error', txt: '系统错误，请联系管理员！' + e })
  }
}

// closeModal 关闭弹出层，并重置表单数据
const closeModal = () => {
  showModal.value = false
  examForm.value = {
    examId: '',
    title: '',
    score: 100,
    examTime: 0,
    beginTime: 0,
    endTime: 0,
    imgNames: '',
    imgUrls: '',
    deptId: '',
    remarks: ''
  }
  times.value = null
  fileObj.value = { id: '', name: '', url: '' }
}

// process 处理
const process = async(id, states) => {
  Confirm('确定要操作该试卷吗？').then(() => {
    procExam(id, states)
  }).catch(() => {
    Msg({ kind: 'info', txt: "您取消了操作！" })
  })
}
// procExam 删除按钮实现，分离出来防止调用时异步报错
const procExam = async (ExamId, states) => {
  loadShow.value = true
  try {
    const res = await procExamsApi({ ExamId, states })
    if(res.code === import.meta.env.VITE_SUCCESS_CODE) {
      await page(0, 1)
      Msg({ kind: 'success', txt: '恭喜您，试卷信息处理成功！' })
    } else {
      Msg({ kind: 'error', txt: res.msg })
    }
    loadShow.value = false
  } catch (e) {
    loadShow.value = false
    Msg({ kind: 'error', txt: '系统错误，请联系管理员！' + e })
  }
}

// 题型
const optList = ref([
  { optId: nanoid(21), examId: curExamId, kind: 1, nums: 80, score: 0.5, remarks: '' },
  { optId: nanoid(21), examId: curExamId, kind: 2, nums: 20, score: 1.0, remarks: '' },
  { optId: nanoid(21), examId: curExamId, kind: 3, nums: 20, score: 2.0, remarks: '' },
  { optId: nanoid(21), examId: curExamId, kind: 4, nums: 0, score: 0.0, remarks: '' },
  { optId: nanoid(21), examId: curExamId, kind: 5, nums: 0, score: 0.0, remarks: '' },
  { optId: nanoid(21), examId: curExamId, kind: 6, nums: 0, score: 0.0, remarks: '' }
])

// fmtDate 时间戳转时间
const fmtDate = computed(() => {
  return (time) => {
    let date = new Date(time*1000)
    return formatDatetime(date)
  }
})

// setUrl 回调获取上传文件的地址
const setUrl = (kind, type, file) => {
  fileObj.value = file
}

const fmtKind = computed(() =>{
  return (kind) => {
    switch (kind) {
      case 1:
        return '单选题'
      case 2:
        return '判断题'
      case 3:
        return '多选题'
      case 4:
        return '填空题'
      case 5:
        return '简答题'
      case 6:
        return '实操题'
      default:
        return '其它'
    }
  }
})

const fmtState = computed(() =>{
  return (state) => {
    switch (state) {
      case 1:
        return '已发布'
      case 3:
        return '已作废'
      default:
        return '其它'
    }
  }
})

const genQrCode = async (examId) => {
  let value = 'http://sc.haobing.pw/#/login/' + examId
  // value = 'http://192.168.1.27:8003/#/login/' + examId
  const canvas = await QRCode.toCanvas(value, { width: 1024, height: 1024 })
  downloadQR2Png(canvas, examId)
}

const downloadQR2Png = (canvas, fileName) => {
  const originalWidth = canvas.width
  const originalHeight = canvas.height
  const borderWidth = 30 // 白边宽度
  const newWidth = originalWidth + 2 * borderWidth
  const newHeight = originalHeight + 2 * borderWidth // 多出的 borderWidth 用于底部文字

  // 创建一个新的 canvas 用于添加白边和文字
  const newCanvas = document.createElement('canvas')
  newCanvas.width = newWidth
  newCanvas.height = newHeight
  const ctx = newCanvas.getContext('2d')

  // 设置背景为白色
  ctx.fillStyle = '#ffffff'
  ctx.fillRect(0, 0, newWidth, newHeight)

  // 绘制原始二维码到新的 canvas 上
  ctx.drawImage(canvas, borderWidth, borderWidth)

  // 下载新的 canvas 图像
  const url = newCanvas.toDataURL()
  const a = document.createElement('a')
  a.download = `${fileName}.png`
  a.href = url
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
}
</script>

<template>
  <div class="exam-a">
    <div class="exam-b">
      <div class="exam-c">
        <div v-if="procAuth.saveAuth" class="btn-pi mr15" title="新增" @click="add"><i class="iconfont">&#xea2d;</i> 新增</div>
        <div class="btn-r mr15" title="筛选" @click="search"><i class="iconfont">&#xea49;</i></div>
        <div class="btn-r mr15" title="刷新" @click="page(0, 1)"><i class="iconfont">&#xea8c;</i></div>
      </div>
      <div class="exam-d"><i class="iconfont">&#xeaaa;</i> 当前位置：工作台 > 试卷管理 > 试卷管理</div>
    </div>
    <div v-show="schShow" class="exam-e">
      <div class="mr15 mt10"><input type="text" v-model="schRef.keywords" maxlength="30" placeholder="请输入关键字" class="sch-ipt" /></div>
      <div class="exam-f mt10">
        <div class="btn-pi mr15" title="搜索" @click="page(0, 1)"><i class="iconfont">&#xea8e;</i> 搜索</div>
        <div class="btn-d" title="重置" @click="clrSch"><i class="iconfont">&#xea4f;</i> 重置</div>
      </div>
    </div>
    <div v-if="hasData">
      <table>
        <tbody>
          <tr>
            <th style="width: 30%;">试卷标题</th>
            <th style="width: 15%;">答题时段</th>
            <th style="width: 10%;">答题时长</th>
            <th style="width: 10%;">状 态</th>
            <th style="width: 10%;">发布时间</th>
            <th style="width: 20%;">操 作</th>
          </tr>
          <tr v-for="curExam in examList" :key="curExam.examId" class="tr-style">
            <td>{{ curExam.title }}({{ curExam.score }}分)</td>
            <td class="txt-center">{{ fmtDate(curExam.beginTime) }} {{ fmtDate(curExam.endTime) }}</td>
            <td class="txt-center">{{ curExam.examTime }}分钟</td>
            <td :class="['txt-center', curExam.states === 1 ? 'color-s' : 'color-e']">{{ fmtState(curExam.states) }}</td>
            <td class="txt-center">{{ fmtDate(curExam.addTime) }}</td>
            <td class="txt-center">
              <span v-if="procAuth.saveAuth" class="cl-warn mr15" title="修改" @click="update(curExam.examId)"><i class="iconfont">&#xea48;</i> 修 改</span>
              <span v-if="procAuth.procAuth" class="cl-error mr15" title="删除" @click="process(curExam.examId, 2)"><i class="iconfont">&#xea48;</i> 删 除</span>
              <span class="cl-blue" title="生成二维码" @click="genQrCode(curExam.examId)"><i class="iconfont">&#xea66;</i> 生 成</span><br />
              <span v-if="procAuth.procAuth" class="cl-success mr15" title="启用" @click="process(curExam.examId, 1)"><i class="iconfont">&#xea48;</i> 启 用</span>
              <span v-if="procAuth.procAuth" class="cur" title="停用" @click="process(curExam.examId, 3)"><i class="iconfont">&#xea48;</i> 停 用</span>
            </td>
          </tr>
        </tbody>
      </table>
      <pager v-if="hasData" :limit="schRef.limit" :total="total" :page="curPage" @turn="page" />
    </div>
    <div v-else class="no-data">暂无内容</div>

    <!-- 新增、修改试卷弹出层 -->
    <transition name="fade-mod" appear>
      <div v-if="showModal" class="modal-backdrop">
        <c-scrollbar>
          <div class="modal" style="width: 600px;">
            <div class="modal-header">
              <div class="header-left"><i class="iconfont">&#xea54;</i> 保存试卷信息</div>
              <div class="header-right" @click="closeModal()"><i class="iconfont fs22">&#xea7f;</i></div>
            </div>
            <div class="modal-body">
              <div>
                <div class="ipt-title"><span class="required">*</span>标题</div>
                <div><input type="text" v-model="examForm.title" maxlength="50" placeholder="请输入试卷标题" class="ipt" /></div>
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>答题时间</div>
                <div><Datepicker v-model="times" range locale="zh-CN" :format="formatDateRange" style="width: 100%;" placeholder="请选择起止时间段" /></div>
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>时长（单位：分钟）</div>
                <div><input type="number" v-model="examForm.examTime" maxlength="10" placeholder="请输入答题时长" class="ipt" /></div>
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>总分（单位：分）</div>
                <div><input type="number" v-model="examForm.score" maxlength="10" placeholder="请输入总分" class="ipt" /></div>
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>附件</div>
                <upload :kind="2" :types="1" :file="fileObj" @setUrl="setUrl" />
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>题量配置</div>
                <div>
                  <div class="exam-g" v-for="cur in optList" :key="cur.optId">
                    <span class="mr15">{{ fmtKind(cur.kind) }}</span>
                    <input type="number" v-model="cur.nums" maxlength="10" placeholder="题量" class="ipt2 mr15" />
                    <input type="number" v-model="cur.score" maxlength="10" placeholder="分值" class="ipt2 mr15" />
                  </div>
                </div>
              </div>
              <div>
                <div class="ipt-title"><span class="required">*</span>备注</div>
                <div><textarea v-model="examForm.remarks" class="desc-txt"></textarea></div>
              </div>
            </div>
            <div class="modal-footer">
              <div class="btn-pi mr15" @click="save"><i class="iconfont">&#xea90;</i> 保存</div>
              <div class="btn-d" @click="closeModal(1)"><i class="iconfont">&#xea4f;</i> 取消</div>
            </div>
          </div>
        </c-scrollbar>
      </div>
    </transition>
    <loader :loadShow="loadShow" />
  </div>
</template>

<style scoped>
.exam-a {padding: 10px;}
.exam-b {padding: 0 20px 10px 20px; display: flex; display: -webkit-flex;}
.exam-c {display: inline-flex; display: -webkit-inline-flex;}
.exam-d {flex-grow: 1; text-align: right; padding-top: 10px; color: #666;}
.exam-e {border: 1px dashed #DDD; padding: 5px 15px 15px 15px; display: flex; display: -webkit-flex; flex-wrap: wrap; margin-bottom: 10px;}
.exam-f {display: inline-flex; display: -webkit-inline-flex;}
.exam-g {width: 100%; display: flex; display: -webkit-flex; padding: 10px 0;}
</style>